﻿using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using LFSRecord2.Model.Replay;
using LFSRecord2.Misc;
using LFSRecord2.Model;
using LFSRecord2.View.TimelineStructures;
using System.Windows.Data;
using System.ComponentModel;
using System.Windows.Media;
using System.Windows.Shapes;

namespace LFSRecord2.View.Dialogs
{
    /// <summary>
    /// Interaction logic for ImportReplayDataFromLFSDialog.xaml
    /// </summary>
    public partial class ImportRpdFromLfsDialog : Window
    {
        enum SetupPages
        {
            ReplayCheck = 0,
            SelectTimespan = 1,
            RecordingData = 2,
            RecordingError = 3,
        }
        SetupPages CurrentPage { get; set; }             // Which setup page are we on right now
        ReplayRecordingErrorEventArgs CurrentError;

        public ImportRpdFromLfsDialog()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // Draw the current page
            CurrentPage = SetupPages.ReplayCheck;
            DrawPage();

            // Setup replay import listeners
            ImportRpdFromLfs importRpd = (ImportRpdFromLfs)DataContext;
            importRpd.ReplayCheckCompleted += new ReplayCheckCompletedEventHandler(importRpd_ReplayCheckCompleted);
            importRpd.ReplayRecordingError += new ReplayRecordingErrorEventHandler(importRpd_ReplayRecordingError);
            importRpd.ReplayRecordingCompleted += new ReplayRecordingCompletedEventHandler(importRpd_ReplayRecordingCompleted);
            importRpd.ReplayRecordingProgress += new EventHandler<ReplayRecordingProgessEventArgs>(importRpd_ReplayRecordingProgress);

            // Start the process by checking the replays
            importRpd.CheckReplay();
        }

        void importRpd_ReplayRecordingError(object sender, ReplayRecordingErrorEventArgs e)
        {
            CurrentPage = SetupPages.RecordingError;
            CurrentError = e;
            DrawPage();
            Debug.WriteLine("Replay import error : " + e.ErrorMessage);
        }

        void importRpd_ReplayCheckCompleted(object sender, ReplayCheckCompletedEventArgs e)
        {
            Debug.WriteLine("Replay Checking Completed");
            Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                new Action(delegate()
                {
                    CurrentPage = SetupPages.SelectTimespan;
                    DrawPage();
                }));
        }

        void importRpd_ReplayRecordingProgress(object sender, ReplayRecordingProgessEventArgs e)
        {
            if (CurrentPage != SetupPages.RecordingData)
                return;

            Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                new Action(delegate()
                {
                    if (ProgressBorder == null)
                    {
                        PageArea.Children.Clear();

                        TextBlock infoText = new TextBlock();
                        infoText.Text = "Recording replay data ...";
                        infoText.TextWrapping = TextWrapping.Wrap;
                        infoText.Margin = new Thickness(10, 10, 10, 10);
                        PageArea.Children.Add(infoText);

                        ProgressBorder = new Border();
                        ProgressBorder.BorderThickness = new Thickness(2);
                        ProgressBorder.Margin = new Thickness(2);
                        ProgressBorder.Padding = new Thickness(2);
                        ProgressBorder.BorderBrush = new SolidColorBrush(Color.FromArgb(255, 141, 141, 141));
                        PageArea.Children.Add(ProgressBorder);

                        ProgressIndicator = new Rectangle();
                        ProgressIndicator.HorizontalAlignment = HorizontalAlignment.Left;
                        ProgressIndicator.Width = 1;
                        ProgressIndicator.Height = 20;
                        ProgressIndicator.Fill = new SolidColorBrush(Colors.Blue);
                        ProgressBorder.Child = ProgressIndicator;
                    }
                    else
                    {
                        ProgressIndicator.Width = e.Progress * ProgressBorder.ActualWidth;
                    }
                }));
        }

        void importRpd_ReplayRecordingCompleted(object sender, ReplayRecordingCompletedEventArgs e)
        {
            Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                 new Action(delegate()
                 {
                     Debug.WriteLine("Replay recording completed. Num players in recording : {0}", e.RData.Players.Count);
                     Debug.WriteLine("First player in RData has {0} packets.", e.RData.Players[0].DataNodes.Count);
                     this.DialogResult = true;
                 }));
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Debug.WriteLine("Closing replay recording dialog window");
            ImportRpdFromLfs importRpd = (ImportRpdFromLfs)DataContext;

            importRpd.ReplayCheckCompleted -= new ReplayCheckCompletedEventHandler(importRpd_ReplayCheckCompleted);

            importRpd.Cancel();
        }

        StackPanel _recordingTimesPanel;
        Border ProgressBorder;
        Rectangle ProgressIndicator;

        void DrawPage()
        {
            TextBlock infoText;

            ImportRpdFromLfs importRpd = (ImportRpdFromLfs)DataContext;

            PageArea.Children.Clear();
            NavigationArea.Children.Clear();

            switch (CurrentPage)
            {
                case SetupPages.ReplayCheck:
                    infoText = new TextBlock();
                    infoText.Text = "Getting replay information from LFS ... please wait";
                    infoText.TextWrapping = TextWrapping.Wrap;
                    infoText.Margin = new Thickness(10, 10, 10, 10);
                    PageArea.Children.Add(infoText);
                    break;

                case SetupPages.SelectTimespan:
                    Grid selectGrid = new Grid();

                    infoText = new TextBlock();
                    infoText.Text = "Select Replay :";
                    infoText.TextWrapping = TextWrapping.Wrap;
                    infoText.HorizontalAlignment = HorizontalAlignment.Left;
                    infoText.Margin = new Thickness(10, 10, 0, 0);
                    selectGrid.Children.Add(infoText);
                    
                    ComboBox rSelect = new ComboBox();
                    rSelect.Width = 210;
                    rSelect.Height = 22;
                    rSelect.HorizontalAlignment = HorizontalAlignment.Left;
                    rSelect.Margin = new Thickness(100, 7, 0, 0);
                    foreach (ImportRpdSectionInfo info in importRpd.RInfo)
                    {
                        rSelect.Items.Add(info.ReplayName);
                    }
                    rSelect.SelectedIndex = 0;
                    rSelect.SelectionChanged += new SelectionChangedEventHandler(rSelect_SelectionChanged);
                    selectGrid.Children.Add(rSelect);
                    PageArea.Children.Add(selectGrid);

                    _recordingTimesPanel = new StackPanel();
                    _recordingTimesPanel.Orientation = Orientation.Vertical;
                    _recordingTimesPanel.Margin = new Thickness(0, 10, 0 ,0);
                    PageArea.Children.Add(_recordingTimesPanel);

                    _selectedReplayIndex = 0;
                    drawTimespanSelectDetails();

                    // Navigation buttons
                    Button ButtonNext = new Button();
                    ButtonNext.Content = "Next";
                    ButtonNext.Width = 54;
                    ButtonNext.Height = 22;
                    ButtonNext.HorizontalAlignment = HorizontalAlignment.Right;
                    ButtonNext.Margin = new Thickness(0, 0, 10, 0);
                    ButtonNext.Click += new RoutedEventHandler(ButtonNext_Click);
                    NavigationArea.Children.Add(ButtonNext);
                    break;

                case SetupPages.RecordingData:
                    // We first inform that we are seeking in replay. Later in the progress callback we draw the actual progress indicator
                    infoText = new TextBlock();
                    infoText.Text = "Seeking in replay ... please wait";
                    infoText.TextWrapping = TextWrapping.Wrap;
                    infoText.Margin = new Thickness(10, 10, 10, 10);
                    PageArea.Children.Add(infoText);
                    break;

                case SetupPages.RecordingError:
                    infoText = new TextBlock();
                    infoText.Text = "An error has occurred :\n\n" + CurrentError.ErrorMessage + " (" + CurrentError.RipError + ")\n\nClick Cancel to close this dialog. Then you can try again.";
                    infoText.TextWrapping = TextWrapping.Wrap;
                    infoText.Margin = new Thickness(10, 10, 10, 10);
                    PageArea.Children.Add(infoText);
                    break;
            }

            // Create and place default items (so far, only cancel button)
            Button buttonCancel = new Button();
            buttonCancel.Content = "Cancel";
            buttonCancel.Width = 54;
            buttonCancel.Height = 22;
            buttonCancel.HorizontalAlignment = HorizontalAlignment.Left;
            buttonCancel.Margin = new Thickness(10, 0, 0, 0);
            buttonCancel.Click += new RoutedEventHandler(buttonCancel_Click);
            NavigationArea.Children.Add(buttonCancel);
        }

        void rSelect_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            e.Handled = true;
            if (e.AddedItems.Count < 1)
                return;
            string item = (string)e.AddedItems[0];

            ImportRpdFromLfs importRpd = (ImportRpdFromLfs)DataContext;
            for (int a = 0; a<importRpd.RInfo.Count; a++)
            {
                if (importRpd.RInfo[a].ReplayName == item)
                {
                    _selectedReplayIndex = a;
                    drawTimespanSelectDetails();
                    break;
                }
            }
        }

        int _selectedReplayIndex = 0;
        void drawTimespanSelectDetails()
        {
            ImportRpdFromLfs importRpd = (ImportRpdFromLfs)DataContext;
            ImportRpdSectionInfo importSection = importRpd.RInfo[_selectedReplayIndex];

            _recordingTimesPanel.Children.Clear();

            // Project times (suggested times)
            TextBlock projectStartEndTime = new TextBlock();
            projectStartEndTime.Text = "Project start / end time : " + TimeHelper.Seconds2TimeStamp(importSection.ProjectStartTime) + " (" + Math.Round(importSection.ProjectStartTime * LfsRecordController.project.FPS) + ") / " + TimeHelper.Seconds2TimeStamp(importSection.ProjectEndTime) + " (" + Math.Round(importSection.ProjectEndTime * LfsRecordController.project.FPS) + ")";
            projectStartEndTime.Margin = new Thickness(10, 1, 10, 1);
            _recordingTimesPanel.Children.Add(projectStartEndTime);

            // Recording start time
            Grid timeBlock = new Grid();
            timeBlock.Height = 20;
            _recordingTimesPanel.Children.Add(timeBlock);

            TextBlock recordStartTime = new TextBlock();
            recordStartTime.Text = "Recording start time :";
            recordStartTime.Margin = new Thickness(10, 3, 0, 0);
            timeBlock.Children.Add(recordStartTime);

            DoubleValueEditControl dec = new DoubleValueEditControl();
            dec.DisplayType = ValueEditControlDisplayTypes.Timestamp;
            dec.ValueName = "RecordStartTime";
            dec.HorizontalAlignment = HorizontalAlignment.Left;
            dec.Height = 18;

            Binding myBinding = new Binding("RecordStartTime");
            myBinding.Mode = BindingMode.TwoWay;
            myBinding.Source = importSection;
            dec.SetBinding(DoubleValueEditControl.ValueProperty, myBinding);
            dec.Margin = new Thickness(130, 3, 0, 0);
            dec.writeLabelValue();

            timeBlock.Children.Add(dec);

            // Recording end time
            timeBlock = new Grid();
            timeBlock.Height = 20;
            _recordingTimesPanel.Children.Add(timeBlock);

            TextBlock recordEndTime = new TextBlock();
            recordEndTime.Text = "Recording end time :";
            recordEndTime.Margin = new Thickness(10, 1, 0, 0);
            timeBlock.Children.Add(recordEndTime);

            dec = new DoubleValueEditControl();
            dec.DisplayType = ValueEditControlDisplayTypes.Timestamp;
            dec.ValueName = "RecordEndTime";
            dec.HorizontalAlignment = HorizontalAlignment.Left;
            dec.Height = 18;

            myBinding = new Binding("RecordEndTime");
            myBinding.Mode = BindingMode.TwoWay;
            myBinding.Source = importSection;
            dec.SetBinding(DoubleValueEditControl.ValueProperty, myBinding);
            dec.Margin = new Thickness(130, 0, 0, 0);
            dec.writeLabelValue();

            timeBlock.Children.Add(dec);

            // Visual time span selector
            //Border brd = new Border();
            //brd.Margin = new Thickness(10, 10, 10, 2);
            //brd.Height = 75;
            //brd.BorderThickness = new Thickness(1);
            //brd.BorderBrush = new SolidColorBrush(Color.FromArgb(255, 141, 141, 141));

            Grid visualSelector = new Grid();
            visualSelector.UseLayoutRounding = true;
            visualSelector.Background = new SolidColorBrush(Colors.White);

            // Create the selector objects
            TimeSelectionGridItem item = new TimeSelectionGridItem();
            item.IsSelected = true;
            item.Margin = new Thickness(10, 10, 10, 2);
            item.HeaderText.Text = importSection.ReplayName;

            myBinding = new Binding("RecordStartTime");
            myBinding.Mode = BindingMode.TwoWay;
            myBinding.Source = importSection;
            item.SetBinding(TimeSelectionGridItem.StartTimeProperty, myBinding);

            myBinding = new Binding("RecordEndTime");
            myBinding.Mode = BindingMode.TwoWay;
            myBinding.Source = importSection;
            item.SetBinding(TimeSelectionGridItem.EndTimeProperty, myBinding);

            item.SuggestedStartTime = importSection.ProjectStartTime;
            item.SuggestedEndTime = importSection.ProjectEndTime;
            item.TotalTime = importSection.ReplayLength;

            //brd.Child = item;
            _recordingTimesPanel.Children.Add(item);

            Debug.WriteLine("Replay length : {0}", importSection.ReplayLength);
        }

        void ButtonNext_Click(object sender, RoutedEventArgs e)
        {
            ImportRpdFromLfs importRpd = (ImportRpdFromLfs)DataContext;

            switch (CurrentPage)
            {
                case SetupPages.ReplayCheck:
                    break;
                case SetupPages.SelectTimespan:
                    importRpd.RecordReplayData(_selectedReplayIndex);

                    // Draw recording page to show progress
                    CurrentPage = SetupPages.RecordingData;
                    DrawPage();
                    break;
                case SetupPages.RecordingData:
                    break;
            }
        }

        void buttonCancel_Click(object sender, RoutedEventArgs e)
        {
            ImportRpdFromLfs importRpd = (ImportRpdFromLfs)DataContext;
            importRpd.Cancel();

            switch (CurrentPage)
            {
                case SetupPages.ReplayCheck:
                    break;
                case SetupPages.SelectTimespan:
                    break;
                case SetupPages.RecordingData:
                    break;
            }

            PageArea.Children.Clear();
            NavigationArea.Children.Clear();
            this.DialogResult = false;
        }
    }
}
